#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "../console/console.h"
#include "driver/gpio.h"
#include "soc/gpio_struct.h"

#include "adc.h"
#include "driver/adc.h"
#include "esp_adc_cal.h"

/*
0 - 107
3200 - 1500
4090 - 1970
*/
/*
4.1 - 充电
4.07 - 充电
4 - 100%
3.6 - 50%
3.2 - 放电
*/
#define UPPER_DIVIDER 442
#define LOWER_DIVIDER 160
#define DEFAULT_VREF    1100        //Use adc2_vref_to_gpio() to obtain a better estimate
#define NO_OF_SAMPLES   64          //Multisampling


static esp_adc_cal_characteristics_t *adc_chars;
static const adc_channel_t channel = ADC_CHANNEL_7;     //GPIO34 if ADC1, GPIO14 if ADC2
static const adc_atten_t atten = ADC_ATTEN_DB_6;
static const adc_unit_t unit = ADC_UNIT_1;

static void check_efuse()
{
    //Check TP is burned into eFuse
    if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK)
    	console_printf(MsgInfo, "eFuse Two Point: Support\r\n");
    else
    	console_printf(MsgInfo, "eFuse Two Point: Not Support\r\n");

    //Check Vref is burned into eFuse
    if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK)
    	console_printf(MsgInfo, "eFuse Vref: Support\r\n");
    else
    	console_printf(MsgInfo, "eFuse Vref: Not Support\r\n");

    console_pause(100);
}


static void print_char_val_type(esp_adc_cal_value_t val_type)
{
    if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP)
    	console_printf(MsgInfo, "Use Two Point Value\r\n");
    else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF)
    	console_printf(MsgInfo, "Use eFuse Vref\r\n");
    else
    	console_printf(MsgInfo, "Use Default Vref\r\n");

    console_pause(100);
}


uint32_t getBatteryVoltage()
{
	uint32_t adc_reading = 0;

    for (int i = 0; i < NO_OF_SAMPLES; i++) {
        if (unit == ADC_UNIT_1) {
        adc_reading += adc1_get_raw((adc1_channel_t)channel);
        } else {
            int raw;
            adc2_get_raw((adc2_channel_t)channel, ADC_WIDTH_BIT_12, &raw);
            adc_reading += raw;
            }
        }

    adc_reading /= NO_OF_SAMPLES;
    uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars) * (LOWER_DIVIDER+UPPER_DIVIDER) / LOWER_DIVIDER;
    return voltage;

	return 0;
}


esp_err_t init_adc()
{
	esp_err_t err = ESP_OK;

	console_printf(MsgInfo, "ADC initialization for measuring VBAT (ADC1, channel=%d, 0 db, Vref=%d mV)\r\n", channel, DEFAULT_VREF);
	console_pause(100);

    //检查Two Point或Vref是否烧入eFuse
    check_efuse();

    //配置 ADC1
    err = adc1_config_width(ADC_WIDTH_BIT_12);
    if (err != ESP_OK)
    {
    	console_printf(MsgError, "Function adc1_config_width() returns error code: %d\r\n", err);
    	return err;
    }

    err = adc1_config_channel_atten(channel, atten);
    if (err != ESP_OK)
    {
    	console_printf(MsgError, "Function adc1_config_channel_atten() returns error code: %d\r\n", err);
    	return err;
    }

    adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t));
    esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, ADC_WIDTH_BIT_12, DEFAULT_VREF, adc_chars);
    print_char_val_type(val_type);

    console_printf(MsgInfo, "The ADC used for VBAT measurement has been initialized\r\n");
	console_pause(300);

	return err;
}

